﻿using Nest;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConcurrentQueueDemo
{
    class CustomTask
    {
        public int Id { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Task t = Demo1.RunProgram();
            t.Wait();
            Console.WriteLine("ok");
            Console.ReadKey();

            //  RunProgram();
        }


        private void DictionaryTest()
        {
            ConcurrentDictionary<int, string> keys = new ConcurrentDictionary<int, string>();
            keys.TryAdd(1, "LL");
            keys.TryAdd(2, "LL");
            Dictionary<int, string> dic = new Dictionary<int, string>();
            dic.Add(1, "OJ");
            dic.Add(2, "R");
            Stopwatch stopwatch = new Stopwatch();

            #region 写入
            stopwatch.Start();
            Parallel.For(0, 2000000, i =>
            {
                lock (dic)
                {
                    dic[i] = new Random().Next(100, 99999).ToString();
                }
            });
            stopwatch.Stop();
            Console.WriteLine("Dictionary加锁写入花费时间：{0}", stopwatch.Elapsed);

            stopwatch.Restart();

            Parallel.For(0, 2000000, i =>
            {
                keys[i] = new Random().Next(100, 99999).ToString();
            });
            stopwatch.Stop();
            Console.WriteLine("ConcurrentDictionary加锁写入花费时间：{0}", stopwatch.Elapsed);
            #endregion


            #region 读取
            string result = string.Empty;
            stopwatch.Restart();
            Parallel.For(0, 2000000, i =>
            {
                lock (dic)
                {
                    result = dic[i];
                }
            });
            stopwatch.Stop();
            Console.WriteLine("Dictionary加锁读取花费时间：{0}", stopwatch.Elapsed);

            stopwatch.Restart();
            Parallel.For(0, 2000000, i =>
            {
                result = keys[i];
            });
            stopwatch.Stop();
            Console.WriteLine("ConcurrentDictionary加锁读取花费时间：{0}", stopwatch.Elapsed);
            #endregion

            Console.ReadLine();
        }



        /// <summary>
        /// 延时取消
        /// </summary>
        /// <returns></returns>
        public async static Task GetToday()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            cts.CancelAfter(3000);
            HttpClient client = new HttpClient();
            var res = await client.GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts.Token);
            var result = await res.Content.ReadAsStringAsync();
            Console.WriteLine(result);
        }

        /// <summary>
        /// 关联取消
        /// </summary>
        /// <returns></returns>
        public async static Task Test()
        {
            CancellationTokenSource cts1 = new CancellationTokenSource();
            CancellationTokenSource cts2 = new CancellationTokenSource();
            var cts3 = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);

            cts1.Token.Register(() =>
            {
                Console.WriteLine("cts1 Canceling");
            });
            cts2.Token.Register(() =>
            {
                Console.WriteLine("cts2 Canceling");
            });
            cts2.CancelAfter(1000);

            cts3.Token.Register(() =>
            {
                Console.WriteLine("root Canceling");
            });

            var res = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts1.Token);
            var result = await res.Content.ReadAsStringAsync();
            Console.WriteLine("cts1:{0}", result);

            var res2 = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts2.Token);
            var result2 = await res2.Content.ReadAsStringAsync();
            Console.WriteLine("cts2:{0}", result2);

            var res3 = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts3.Token);
            var result3 = await res2.Content.ReadAsStringAsync();
            Console.WriteLine("cts3:{0}", result3);
        }



        static async Task RunProgram()
        {
            var taskQueue = new ConcurrentQueue<CustomTask>();
            var cts = new CancellationTokenSource();
            //生成任务添加至并发队列
            var taskSource = Task.Run(() => TaskProducer(taskQueue));
            //同时启动四个任务处理队列中的任务
            Task[] processors = new Task[4];
            for (int i = 1; i <= 4; i++)
            {
                string processId = i.ToString();
                processors[i - 1] = Task.Run(
                () => TaskProcessor(taskQueue, "Processor " + processId, cts.Token)
                );
            }
            await taskSource;
            //向任务发送取消信号
            cts.CancelAfter(TimeSpan.FromSeconds(2));
            await Task.WhenAll(processors);

            Console.ReadKey();
        }

        // 产生任务
        static async Task TaskProducer(ConcurrentQueue<CustomTask> queue)
        {
            for (int i = 0; i < 20; i++)
            {
                await Task.Delay(50);
                var workItem = new CustomTask { Id = i };
                queue.Enqueue(workItem);
                Console.WriteLine("task {0} has been posted", workItem.Id);
            }
        }
        // 执行任务

        static async Task TaskProcessor(ConcurrentQueue<CustomTask> queue, string name, CancellationToken token)
        {
            CustomTask workItem;
            bool dequeueSuccesful = false;
            await GetRandomDelay();
            do
            {
                dequeueSuccesful = queue.TryDequeue(out workItem);
                if (dequeueSuccesful)
                {
                    Console.WriteLine("task {0} has been processed by {1}", workItem.Id, name);
                }
                await GetRandomDelay();
            }
            while (!token.IsCancellationRequested);
        }

        static Task GetRandomDelay()
        {
            int delay = new Random(DateTime.Now.Millisecond).Next(1500);
            return Task.Delay(delay);
        }


        class CustomTask
        {
            public int Id { get; set; }
        }

    }
}
